﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Acoris.Foundation
{
    /// <summary>
    /// 
    /// </summary>
    public static class Hash
    {
        public static int SDBMHash(string text)
        {
            //unsigned int SDBMHash(char* str)
            //{
            //    unsigned int hash = 0;

            //    while (*str) {
            //        // equivalent to: hash = 65599*hash + (*str++);
            //        hash = (*str++) + (hash << 6) + (hash << 16) - hash;
            //    }

            //    return (hash & 0x7FFFFFFF);
            //}
            int hash = 0;
            foreach (short ch in text) {
                hash = ch + (hash << 6) + (hash << 16) - hash;
            }
            return (hash & 0x7FFFFFFF);
        }

        public static int RSHash(string text)
        {
            //// RS Hash Function
            //unsigned int RSHash(char* str)
            //{
            //    unsigned int b = 378551;
            //    unsigned int a = 63689;
            //    unsigned int hash = 0;

            //    while (*str) {
            //        hash = hash * a + (*str++);
            //        a *= b;
            //    }

            //    return (hash & 0x7FFFFFFF);
            //}
            int hash = 0;
            int a = 378551,b = 63689;
            foreach (short ch in text) {
                hash = hash * a + ch;
                a *= b;
            }
            return (hash & 0x7FFFFFFF);
        }

        public static int JSHash(string text)
        {
            //// JS Hash Function
            //unsigned int JSHash(char* str)
            //{
            //    unsigned int hash = 1315423911;

            //    while (*str) {
            //        hash ^= ((hash << 5) + (*str++) + (hash >> 2));
            //    }

            //    return (hash & 0x7FFFFFFF);
            //}
            int hash = 0;
            foreach (short ch in text) {
                hash ^= ((hash << 5) + ch + (hash >> 2));
            }
            return (hash & 0x7FFFFFFF);
        }

        public static int PJWHash(string text)
        {
            //// P. J. Weinberger Hash Function
            //unsigned int PJWHash(char* str)
            //{
            //    unsigned int BitsInUnignedInt = (unsigned int)(sizeof(unsigned int) *8);
            //    unsigned int ThreeQuarters    = (unsigned int)((BitsInUnignedInt * 3) / 4);
            //    unsigned int OneEighth        = (unsigned int)(BitsInUnignedInt / 8);
            //    unsigned int HighBits         = (unsigned int)(0xFFFFFFFF) << (BitsInUnignedInt - OneEighth);
            //    unsigned int hash             = 0;
            //    unsigned int test             = 0;

            //    while (*str) {
            //        hash = (hash << OneEighth) + (*str++);
            //        if ((test = hash & HighBits) != 0) {
            //            hash = ((hash ^ (test >> ThreeQuarters)) & (~HighBits));
            //        }
            //    }

            //    return (hash & 0x7FFFFFFF);
            //}
            uint BitsInUnignedInt = 4 * 8;
            uint ThreeQuarters = (uint)((BitsInUnignedInt * 3 )/ 4);
            uint OneEighth  = BitsInUnignedInt / 8;
            uint HighBits   = (uint)((0xFFFFFFFF) << ((int)BitsInUnignedInt - (int)OneEighth));
            uint test = 0;

            int hash = 0;
            foreach (short ch in text) {
                hash = (hash << (int)OneEighth) + ch;
                test = (uint)hash & HighBits;
                if(test != 0) {
                    hash = (int)((hash ^ (test >> (int)ThreeQuarters)) & (~(int)HighBits));
                }
            }
            return (hash & 0x7FFFFFFF);
        }

        public static int ELFHash(string text)
        {
            //// ELF Hash Function
            //unsigned int ELFHash(char* str)
            //{
            //    unsigned int hash = 0;
            //    unsigned int x    = 0;

            //    while (*str) {
            //        hash = (hash << 4) + (*str++);
            //        if ((x = hash & 0xF0000000L) != 0) {
            //            hash ^= (x >> 24);
            //            hash &= ~x;
            //        }
            //    }

            //    return (hash & 0x7FFFFFFF);
            //}
            int hash = 0;
            int x = 0;
            foreach (short ch in text) {
                hash = (hash << 4) + ch;
                x = (int)(hash & 0xF0000000);
                if (x != 0) {
                    hash ^= (x >> 24);
                    hash &= ~x;
                }
            }
            return (hash & 0x7FFFFFFF);
        }

        public static int BKDRHash(string text)
        {
            //// BKDR Hash Function
            //unsigned int BKDRHash(char* str)
            //{
            //    unsigned int seed = 131; // 31 131 1313 13131 131313 etc..
            //    unsigned int hash = 0;

            //    while (*str) {
            //        hash = hash * seed + (*str++);
            //    }

            //    return (hash & 0x7FFFFFFF);
            //}
            int seed = 131;
            int hash = 0;
            foreach (short ch in text) {
                hash = hash * seed + ch;
            }
            return (hash & 0x7FFFFFFF);
        }

        public static int APHash(string text)
        {
            //// AP Hash Function
            //unsigned int APHash(char* str)
            //{
            //    unsigned int hash = 0;
            //    int i;

            //    for (i = 0; *str; i++) {
            //        if ((i & 1) == 0) {
            //            hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3));
            //        }
            //        else {
            //            hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5)));
            //        }
            //    }

            //    return (hash & 0x7FFFFFFF);
            //}
            int hash = 0;
            int i = 0;
            foreach(short ch in text) {
                if((i & 1) == 0) {
                    hash ^= ((hash << 7) ^ ch ^ (hash >> 3));
                }
                else {
                    hash ^= (~((hash << 11) ^ ch ^ (hash >> 5)));
                }
                i++;
            }
            return (hash & 0x7FFFFFFF);
        }

        public static int BJDHash(string text)
        {
            //// DJB Hash Function
            //unsigned int DJBHash(char* str)
            //{
            //    unsigned int hash = 5381;

            //    while (*str) {
            //        hash += (hash << 5) + (*str++);
            //    }

            //    return (hash & 0x7FFFFFFF);
            //}
            int hash = 5381;
            foreach(short ch in text) {
                hash += (ch << 5) + ch;
            }
            return (hash & 0x7FFFFFFF);
        }
    }
}
